﻿// Fill out your copyright notice in the Description page of Project Settings.


#include "Actor/StarrySkyProjectile.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "AbilitySystem/StarrySkyAbilitySystemLibrary.h"
#include "Components/AudioComponent.h"
#include "Components/SphereComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Kismet/GameplayStatics.h"
#include "StarrySky/StarrySky.h"


AStarrySkyProjectile::AStarrySkyProjectile()
{
	PrimaryActorTick.bCanEverTick = false;
	//服务器复制设置为true，这样客户端就可以复制抛射物
	bReplicates = true;
	//添加碰撞球体
	Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
	SetRootComponent(Sphere);
	//设置碰撞类型
	Sphere->SetCollisionObjectType(ECC_Projectile);
	//设置碰撞检测仅查询
	Sphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	//先把全部通道设置为忽略
	Sphere->SetCollisionResponseToAllChannels(ECR_Ignore);
	//设置世界动态，世界静态，和棋子通道检测为重叠，这样动态物体就是重叠
	Sphere->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Overlap);
	Sphere->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Overlap);
	Sphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
	//设置投射物运动组件
	ProjectileMovement= CreateDefaultSubobject<UProjectileMovementComponent>("ProjectileMovement");
	//设置初始速度和最大速度，设置相同速度就不会加速运动
	ProjectileMovement->InitialSpeed= 550.0f;
	ProjectileMovement->MaxSpeed= 550.0f;
	//设置重力比例为0没有重力
	ProjectileMovement->ProjectileGravityScale= 0.0f;
}

void AStarrySkyProjectile::BeginPlay()
{
	Super::BeginPlay();
	//设置持续生命周期
	SetLifeSpan(LifeSpan);
	//服务器复制actor的运动效果
	SetReplicateMovement(true);
	//添加重叠事件
	Sphere->OnComponentBeginOverlap.AddDynamic(this, &AStarrySkyProjectile::OnSphereOverlap);
	//设置循环播放音效组件到根组件中
	LoopIngSoundComponent = UGameplayStatics::SpawnSoundAttached(ImpactSound, GetRootComponent());
}

void AStarrySkyProjectile::Destroyed()
{
	//删除虚幻播放音效的组件
	if (LoopIngSoundComponent)
	{
		LoopIngSoundComponent->Stop();
		//组件销毁
		LoopIngSoundComponent->DestroyComponent();
	}
	Super::Destroyed();
}

void AStarrySkyProjectile::OnHit()
{
	//播放声音,在Actor所在的位置
	UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation(),FRotator::ZeroRotator);
	//播放粒子特效
	UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ImpactEffect, GetActorLocation(), FRotator::ZeroRotator);
	if (LoopIngSoundComponent)
	{
		LoopIngSoundComponent->Stop();
		//组件销毁
		LoopIngSoundComponent->DestroyComponent();
	}
	bHit=true;
}

void AStarrySkyProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
                                           UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (!IsValidOverlap(OtherActor)) return;
	//这里加入当服务端没有发生碰撞的时候播放声音和特效
	if (!bHit)
	{
		OnHit();
	}
	//如果在服务器上需要处理销毁该物体
	if(HasAuthority())
	{
		//对目标施加伤害的游戏效果
		if(UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(OtherActor))
		{
			//计算死亡冲力的向量
			FVector DeathImpulse = DamageEffectParams.DeathImpulseMagnitude * GetActorForwardVector();
			DamageEffectParams.DeathImpulse= DeathImpulse;
			//计算击退的向量
			//首要根据击退几率判断是否要击退
			const bool bKnockback = FMath::RandRange(0.f, 100.f) < DamageEffectParams.KnockbackChance;
			if (bKnockback)
			{
				//获取抛射物的旋转FRotator
				FRotator Rotation = GetActorRotation();
				//旋转向量延Y轴正向旋转45度，相当于抬起头45度
				Rotation.Pitch = 45.f;
				//获取旋转向量
				const FVector KnockbackDirection = Rotation.Vector();
				//根据击退数值乘以旋转向量放大向量值
				FVector KnockbackForce = DamageEffectParams.KnockbackForceMagnitude * KnockbackDirection;
				DamageEffectParams.KnockbackForce= KnockbackForce;
			}
			
			//这里我们获取了目标的能力系统组件，可以将目标能力系统组件设置到伤害效果参数中
			DamageEffectParams.TargetAbilitySystemComponent=TargetASC;
			//使用Aura能力系统蓝图函数库施加伤害效果
			//UStarrySkyAbilitySystemLibrary::ApplyDamageEffect(DamageEffectParams);
			//通能能力系统蓝图函数库获取能力系统组件
			const UAbilitySystemComponent* SourceASC=DamageEffectParams.SourceAbilitySystemComponent;
			//制作效果上下文
			FGameplayEffectContextHandle DamageEffectContext = SourceASC->MakeEffectContext();
			DamageEffectContext.AddSourceObject(SourceASC->GetAvatarActor());
			//制作伤害游戏效果的规格句柄,这里可以直接传入能力的等级
			const FGameplayEffectSpecHandle DamageEffectSpecHandle=SourceASC->MakeOutgoingSpec(DamageEffectParams.DamageGameplayEffectClass,DamageEffectParams.AbilityLevel,DamageEffectContext);
			TargetASC->ApplyGameplayEffectSpecToSelf(*DamageEffectSpecHandle.Data.Get());
		}
		Destroy();
	}else
	{
		//客户端设置为已经发生重叠的碰撞了
		bHit=true;
	}
}

bool AStarrySkyProjectile::IsValidOverlap(const AActor* OtherActor) const
{
	//获取能力源对象,这里需要判断参数中的能力组件是否为空，客户端可能为空
	if (DamageEffectParams.SourceAbilitySystemComponent==nullptr) return false;
	const AActor* SourceActor = DamageEffectParams.SourceAbilitySystemComponent->GetAvatarActor();
	if (SourceActor==nullptr) return false;
	//重叠对象是能力的源对象则返回
	if (SourceActor==OtherActor) return false;
	//判断重叠的目标是否为友军,要从能力效果规范句柄中找出原因对象也就是产生能力的对象
	if (!UStarrySkyAbilitySystemLibrary::IsNotFriend(SourceActor, OtherActor)) return false;
	return true;
}

